package com.ftrend.printdemo.mhttemplate;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.text.TextPaint;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 页面排版
 *
 * @author mapleaf
 * @date 2022/09/08
 */
public class PrinterPaper {
    private final Context context;
    private final Size size;
    private int printNum = 1;

    /**
     * 行间距
     */
    private final int lineSpacing;
    //默认打印字体26
    private float fontSize = 24;

    private float fontSizeLess = 22;
    private float fontSizeNormal = 26;
    private float fontSizeLarge = 30;

    private final Bitmap data;
    private final Canvas canvas;
    private final Paint paint;

    private final float minPixelY;
    private final float minPixelX;
    private final float maxPixelX;
    private final float centerPixelX;
    private float baselineY;

    /**
     * 构建排版纸张
     *
     * @param size        纸张大小
     * @param margin      纸张空白边距
     * @param lineSpacing 行距
     */
    public PrinterPaper(Context context, Size size, Margin margin, int lineSpacing) {
        this.context = context;
        this.size = size;
        this.lineSpacing = lineSpacing;

        this.data = Bitmap.createBitmap(size.getWidth() * 8, size.getHeight() * 8, Bitmap.Config.RGB_565);

        this.canvas = new Canvas(data);
        canvas.drawColor(Color.WHITE);
        canvas.setDensity(data.getDensity());

        this.minPixelX = margin.getLeft();
        this.minPixelY = margin.getTop();
        this.maxPixelX = data.getWidth() - margin.getRight();
        this.centerPixelX = minPixelX + (maxPixelX - minPixelX) / 2;
        //this.typeface =  Typeface.createFromAsset(context.getAssets(), "font/simsun.ttc");
        this.baselineY = minPixelY;

        this.paint = new Paint();
        resetPaint();
    }

    /**
     * 添加一行文本
     *
     * @param text  文本
     * @param style 样式
     */
//    public void addLineText(String text, Style style) {
//        drawTextElement(text, style, new LineElementBox(round(minPixelX, RoundingMode.DOWN), round(maxPixelX, RoundingMode.DOWN)));
//    }
    public void addLineText(String text, Style style,Typeface typeface) {
        drawTextElement(text, style, new LineElementBox(round(minPixelX, RoundingMode.DOWN), round(maxPixelX, RoundingMode.DOWN)),typeface);
    }

    /**
     * 添加分割线
     *
     * @param w 分割线宽度
     */
    public void addHr(float w) {
        paint.setStrokeWidth(w);

        addLineSpacing(-1);
        canvas.drawLine(minPixelX, baselineY + (paint.getStrokeWidth() / 2), maxPixelX, baselineY + (paint.getStrokeWidth() / 2), paint);
        baselineY += paint.getStrokeWidth();
        resetPaint();
    }

    /**
     * 添加空行
     *
     * @param h 高度
     */
    public void addBlankLine(float h) {
        baselineY += h;
    }

    /**
     * 添加一张位图
     *
     * @param bitmap 位图
     * @param style  样式
     */
    public void addBitmap(Bitmap bitmap, Style style) {
        if (Objects.isNull(bitmap)) {
            return;
        }

        addLineSpacing(style.getLineSpacing());
        float x = 0;
        switch (style.getAlign()) {
            case LEFT:
                x = minPixelX;
                break;
            case CENTER:
                x = centerPixelX - Math.floorDiv(bitmap.getWidth(), 2);
                break;
            case RIGHT:
                x = maxPixelX - bitmap.getWidth();
                break;
        }
        canvas.drawBitmap(bitmap, x, baselineY, paint);
        resetPaint();
        baselineY += bitmap.getHeight();
    }

    /**
     * 添加一张条码
     *
     * @param barCode 条码
     * @param style   样式
     * @throws WriterException 条码生成异常
     */
    public void addBarCode(BarCodeElement barCode, Style style) throws WriterException {
        if (barCode.getFormat() != BarcodeFormat.QR_CODE) {
            int width = round(maxPixelX - minPixelX, RoundingMode.UP);
            barCode.setSize(width, width / 5);
        }
        addBitmap(barCode.toBitmap(), style);
    }
    //Typeface.createFromAsset(context.getAssets(), "font/simsun.ttc")
    private void drawTextElement(String text, Style style, LineElementBox box,Typeface typeface) {
        if (Objects.isNull(text) || Objects.equals("", text)) {
            return;
        }
        Rect textRect = new Rect();
        TextPaint textPaint = new TextPaint(paint);
        textPaint.setFlags(Paint.FILTER_BITMAP_FLAG);
        textPaint.setAntiAlias(true);
        textPaint.setStrokeWidth(0.44f);
        textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        textPaint.setTypeface(typeface);
        textPaint.setTextSize(fontSize(style.getFontSize()));
        textPaint.setTextAlign(Paint.Align.valueOf(style.getAlign().name()));
        textPaint.getTextBounds(text, 0, text.length(), textRect);

        float x = 0;
        int height = textRect.height();
        addLineSpacing(style.getLineSpacing());
        baselineY += height;

        switch (style.getAlign()) {
            case LEFT:
                x = box.getStart();
                break;
            case CENTER:
                x = box.getCenter();
                break;
            case RIGHT:
                x = box.getEnd();
                break;
        }
        canvas.drawText(text, x, baselineY, textPaint);
        resetPaint();
    }
    private void drawTextElement(String text, Style style, LineElementBox box) {
        if (Objects.isNull(text) || Objects.equals("", text)) {
            return;
        }
        Rect textRect = new Rect();
        TextPaint textPaint = new TextPaint(paint);
        textPaint.setFlags(Paint.FILTER_BITMAP_FLAG);
        textPaint.setAntiAlias(true);
        textPaint.setStrokeWidth(0.74f);
        textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        textPaint.setTypeface(Typeface.createFromAsset(context.getAssets(), "font/simsun.ttc"));
        textPaint.setTextSize(fontSize(style.getFontSize()));
        textPaint.setTextAlign(Paint.Align.valueOf(style.getAlign().name()));
        textPaint.getTextBounds(text, 0, text.length(), textRect);

        float x = 0;
        int height = textRect.height();
        addLineSpacing(style.getLineSpacing());
        baselineY += height;

        switch (style.getAlign()) {
            case LEFT:
                x = box.getStart();
                break;
            case CENTER:
                x = box.getCenter();
                break;
            case RIGHT:
                x = box.getEnd();
                break;
        }
        canvas.drawText(text, x, baselineY, textPaint);
        resetPaint();
    }

    /**
     * 获取纸张大小
     *
     * @return 纸张大小
     */
    public Size getSize() {
        return size;
    }

    /**
     * 获取预览图
     *
     * @return 预览图
     */
    public Bitmap getPreview() {
        Bitmap bitmap = data.copy(Bitmap.Config.ARGB_8888, true);

        ColorMatrix matrix = new ColorMatrix();
        matrix.setSaturation(0);
        ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
        Paint p = new Paint();
        p.setColorFilter(filter);

        new Canvas(bitmap).drawBitmap(data, 0, 0, p);
        return bitmap;
    }

    /**
     * 获取最终打印数据
     *
     * @return 打印数据
     */
    public List<Byte> getPrintData() {
        Bitmap bitmap = Bitmap.createBitmap(data, 0, 0, data.getWidth(), data.getHeight());
        return bitmapToBytes(bitmap);
    }

    private void addLineSpacing(int ls) {
        if (baselineY != minPixelY) {
            baselineY += (ls > 0 ? ls : lineSpacing);
        }
    }

    private float fontSize(float size) {
        return (size == 0F ? fontSize : size);
    }

    public float getDefaultFontSize() {
        return fontSize;
    }

    public void setDefaultFontSize(float fontSize) {
        this.fontSize = fontSize;
    }

    public int getPrintNum() {
        return printNum;
    }

    public void setPrintNum(int printNum) {
        this.printNum = printNum;
    }

    public void resetPaint() {
        this.paint.reset();
    }

    private int round(float v, RoundingMode mode) {
        return new BigDecimal(v).setScale(0, mode).intValue();
    }

    private List<Byte> bitmapToBytes(Bitmap bitmap) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        List<Byte> bytes = new ArrayList<>();

        int[] p = new int[8];
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width / 8; j++) {
                for (int k = 0; k < 8; k++) {
                    int grey = bitmap.getPixel(j * 8 + k, i);
                    int red = ((grey & 0x00FF0000) >> 16);
                    int green = ((grey & 0x0000FF00) >> 8);
                    int blue = (grey & 0x000000FF);
                    int gray = (int) (0.29900 * red + 0.58700 * green + 0.11400 * blue); // 灰度转化公式
                    if (gray <= 180) {
                        p[k] = 0;
                    } else {
                        p[k] = 1;
                    }
                }

                int value = p[0] * 128 + p[1] * 64 + p[2] * 32 + p[3] * 16 + p[4] * 8 + p[5] * 4 + p[6] * 2 + p[7];
                bytes.add((byte) value);
            }
        }
        return bytes;
    }
}
